﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using UnityEngine;
class ObjCopy
{
    public static T DeepCopy<T>(T RealObject)
    {
        using (Stream objectStream = new MemoryStream())
        {
            //利用 System.Runtime.Serialization序列化与反序列化完成引用对象的复制  
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(objectStream, RealObject);
            objectStream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(objectStream);
        }
    }
}

public class xmlConfigure
{
	public xmlConfigure (string strFileName)
	{
        XmlDocument doc = new XmlDocument();
		doc.Load(strFileName);
        m_uiTemplate = LoadUITemplate(doc);
        m_uiRelationTemplate = LoadUIRelationTemplate(doc);
        m_objWithUI = LoadObjWithUI(doc);
    }

    Dictionary<string, uiTemplate> LoadUITemplate(XmlDocument doc)
    {
        Dictionary<string, uiTemplate> ret = new Dictionary<string, uiTemplate>();
        XmlNodeList uiObjList = doc.SelectNodes("Configure/uiDefine/uiTemplateDef");
        foreach (XmlNode uiObj in uiObjList)
        {
            uiTemplate templateUI = new uiTemplate();
            templateUI.TemplateID = uiObj.Attributes["id"].Value;
            XmlNodeList nodeParamList = uiObj.SelectNodes("param");
            foreach (XmlNode nodeParam in nodeParamList)
            {
                uiParam param = new uiParamReal();
                string strScope = nodeParam.Attributes["scope"].Value;
                string[] lsStr = strScope.Split(';');

                string strValue = nodeParam.Attributes["value"].Value;
                string type = nodeParam.Attributes["type"].Value;
                switch (type)
                {
                    case "real":
                        {
                            param = new uiParamReal();
                            uiParamReal realParam = param as uiParamReal;
                            realParam.Value = float.Parse(strValue);
                            realParam.SetScope(float.Parse(lsStr[0].Trim()), float.Parse(lsStr[1].Trim()));
                            break;
                        }
                    case "int":
                        {
                            param = new uiParamInt();
                            uiParamInt intParam = param as uiParamInt;
                            intParam.Value = int.Parse(strValue);
                            intParam.SetScope(int.Parse(lsStr[0].Trim()), int.Parse(lsStr[1].Trim()));
                            break;
                        }
                    case "string":
                        {
                            param = new uiParamString();
                            uiParamString strParam = param as uiParamString;
                            strParam.Value = strValue;
                            break;
                        }
                    case "list":
                        {
                            param = new uiParamList();
                            uiParamList lsParam = param as uiParamList;
                            lsParam.SelIndex = int.Parse(strValue); ;
                            lsParam.ListValue = lsStr;
                            break;

                        }
                    case "offset":
                        {
                            param = new uiParamOffset();
                            uiParamOffset offsetParam = param as uiParamOffset;
                            float xAxis = float.Parse(nodeParam.Attributes["xAxis"].Value.Trim());
                            float yAxis = float.Parse(nodeParam.Attributes["yAxis"].Value.Trim());
                            float zAxis = float.Parse(nodeParam.Attributes["zAxis"].Value.Trim());
                            offsetParam.SetAxis(xAxis, yAxis, zAxis);
                            offsetParam.SetScope(float.Parse(lsStr[0].Trim()), float.Parse(lsStr[1].Trim()));
                            offsetParam.OffsetValue = float.Parse(strValue);
                        }
                        break;
                    case "rotate":
                        {
                            param = new uiParamRotate();
                            uiParamRotate rotateParam = param as uiParamRotate;
                            float xAxis = float.Parse(nodeParam.Attributes["xAxis"].Value.Trim());
                            float yAxis = float.Parse(nodeParam.Attributes["yAxis"].Value.Trim());
                            float zAxis = float.Parse(nodeParam.Attributes["zAxis"].Value.Trim());
                            rotateParam.SetAxis(xAxis, yAxis, zAxis);
                            rotateParam.SetScope(float.Parse(lsStr[0].Trim()), float.Parse(lsStr[1].Trim()));
                            rotateParam.RotateValue = float.Parse(strValue);
                            break;
                        }
                }

                string strID = nodeParam.Attributes["id"].Value;
                string strDes = nodeParam.Attributes["des"].Value;
                param.Des = strDes;
                param.ID = strID;
                templateUI.AddParam(param);
            }
            ret.Add(templateUI.TemplateID, templateUI);
        }
        return ret;
    }
    Dictionary<string, UIRelationTemplate> LoadUIRelationTemplate(XmlDocument doc)
    {
        Dictionary<string, UIRelationTemplate> ret = new Dictionary<string, UIRelationTemplate>();
        XmlNodeList uiObjList = doc.SelectNodes("Configure/uiObjDefine/uiRelationTemplate");
        foreach (XmlNode uiObj in uiObjList)
        {
            string idTemplate;
            UIRelationTemplate obj = new UIRelationTemplate();
            obj.Id = uiObj.Attributes["id"].Value;
            idTemplate = uiObj.Attributes["idTemplate"].Value;
            obj.Template = ObjCopy.DeepCopy<uiTemplate>(m_uiTemplate[idTemplate]);
            ret.Add(obj.Id, obj);
        }
        return ret;
    }
    Dictionary<string, ObjRelationUI> LoadObjWithUI(XmlDocument doc)
    {
        Dictionary<string, ObjRelationUI> ret = new Dictionary<string, ObjRelationUI>();
        XmlNodeList uiObjList = doc.SelectNodes("Configure/objConfigure/ObjWithUI");
        foreach (XmlNode uiObj in uiObjList)
        {
            string idUI;
            ObjRelationUI obj = new ObjRelationUI();
            obj.ObjName = uiObj.Attributes["objName"].Value;
            idUI = uiObj.Attributes["uiId"].Value;
            uiTemplate template = new uiTemplate();
            obj.UI = m_uiRelationTemplate[idUI];
            ret.Add(obj.ObjName, obj);
        }
        return ret;
    }

    Dictionary<string, uiTemplate> m_uiTemplate;
    Dictionary<string, UIRelationTemplate> m_uiRelationTemplate;
    Dictionary<string, ObjRelationUI> m_objWithUI;

    static xmlConfigure m_cfg;
    static public  xmlConfigure GetInstance()
    {
        if(m_cfg == null)
        {
            m_cfg = new xmlConfigure("Assets\\configure\\configureObj.xml");
        }
        return m_cfg;
    }

    public ObjRelationUI GetObjUI(string objName)
    {
        return m_objWithUI[objName];
    }
}
[Serializable]
public class ObjRelationUI
{
    string m_ObjName;
    public string ObjName
    {
        get { return m_ObjName; }
        set { m_ObjName = value; }
    }
    UIRelationTemplate m_pUI;
    public UIRelationTemplate UI
    {
        get { return m_pUI; }
        set { m_pUI = value; }
    }
}
[Serializable]
public class UIRelationTemplate
{
    string m_id;
    public string Id
    {
        get { return m_id; }
        set { m_id = value; }
    }
    uiTemplate m_Template;
    public uiTemplate Template
    {
        get { return m_Template; }
        set { m_Template = value; }
    }

    void CreateUI()
    {
        m_Template.CreateUI();
    }
}
[Serializable]
public class uiTemplate
{
    List<uiParam> m_vParam = new List<uiParam>();
    string m_templateID;
    public string TemplateID
    {
        get { return m_templateID; }
        set { m_templateID = value; }
    }
    public void AddParam(uiParam param)
    {
        m_vParam.Add(param);
    }
    public void Clear()
    {
        m_vParam.Clear();
    }

    public void CreateUI()
    {
        GUILayout.Label(m_templateID);
        foreach (uiParam param in m_vParam)
        {
            param.CreateUI();
        }
    }

}
[Serializable]
public class uiParam
{
	public enum emType
	{
		TYPE_REAL = 0,
		TYPE_INT,
		TYPE_LIST,
		TYPE_STRING,
		TYPE_OFFSET,
		TYPE_ROTATE
	}
    public uiParam.emType Type
    {
        get { return m_type; }
        set { m_type = value; }
    }
    public string ID
    {
        get { return m_uiID; }
        set { m_uiID = value; }
    }
    public string Des
    {
        get { return m_des; }
        set { m_des = value; }
    }
	public virtual void CreateUI()
	{
		return;
	}

	protected float CreateRealInput(string strName, float fIn)
	{
		GUILayout.BeginHorizontal ();
		GUILayout.Label (strName);
		string strValue = GUILayout.TextField (fIn.ToString ());
		float fValue;
		if (!float.TryParse (strValue, out fValue))
			fValue = 0;
		GUILayout.EndHorizontal ();
		return fValue;
	}

	protected float CreateRealInput(string strName, float fIn, float fMin, float fMax)
	{
		float fValue = CreateRealInput (strName, fIn);
		if (fValue < fMin)
			fValue = fMin;
		if (fValue > fMax)
			fValue = fMax;
		return fValue;
	}

	protected int CreateIntInput(string strName, int iIn)
	{
		GUILayout.BeginHorizontal ();
		GUILayout.Label (strName);
		string strValue = GUILayout.TextField (iIn.ToString ());
		int iValue;
		if (!int.TryParse (strValue, out iValue))
			iValue = 0;
		GUILayout.EndHorizontal ();
		return iValue;
	}

	protected int CreateIntInput(string strName, int iIn, int iMin, int iMax)
	{
		int iValue = CreateIntInput (strName, iIn);
		if (iValue < iMin)
			iValue = iMin;
		if (iValue > iMax)
			iValue = iMax;
		return iValue;
	}

	protected string CreateStringInput(string strName, string strIn)
	{
		GUILayout.BeginHorizontal ();
		GUILayout.Label (strName);
		string strValue = GUILayout.TextField (strIn.ToString ());
		GUILayout.EndHorizontal ();
		return strValue;
	}

    protected int CreateListInput(string strName, string[] strIn, int iSel)
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(strName);
        int iRet = GUILayout.SelectionGrid(iSel, strIn, 1);
        GUILayout.EndHorizontal();
        return iRet;
    }

    protected void  CreateReadAxis(string strName, UnityEngine.Vector3 fIn)
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(strName);

        GUILayout.Label(fIn[0].ToString());
        GUILayout.Label(fIn[1].ToString());
        GUILayout.Label(fIn[2].ToString());

        GUILayout.EndHorizontal();
    }

    protected UnityEngine.Vector3 CreateEditAxis(string strName, UnityEngine.Vector3 fIn)
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label(strName);
		UnityEngine.Vector3 ret = new Vector3();

        string strValue = GUILayout.TextField(fIn[0].ToString());
        float fValue;
        if (!float.TryParse(strValue, out fValue))
            ret[0] = 0;
		else ret[0] = fValue;
        strValue = GUILayout.TextField(fIn[1].ToString());
        if (!float.TryParse(strValue, out fValue))
            ret[1] = 0;
		else ret[1] = fValue;

        strValue = GUILayout.TextField(fIn[2].ToString());
        if (!float.TryParse(strValue, out fValue))
            ret[2] = 0;
		else ret[2] = fValue;

        GUILayout.EndHorizontal();
		ret.Normalize ();
		return ret;
    }

    string m_des;
    string m_uiID;
    emType m_type;
}

[Serializable]
public class uiParamReal : uiParam
{
    public uiParamReal()
    {
		Type = uiParam.emType.TYPE_REAL;
    }
    float m_fValue;
    public float Value
    {
        get { return m_fValue; }
        set { m_fValue = value; }
    }
    float m_fMin, m_fMax;
    public void SetScope(float fMin, float fMax)
    {
        m_fMax = fMax;
        m_fMin = fMin;
    }
    public  void GetScope(ref float fMin, ref float fMax)
    {
        fMin = m_fMin;
        fMax = m_fMax;
    }

	public override void CreateUI()
    {
		m_fValue = CreateRealInput (Des, m_fValue, m_fMin, m_fMax);
    }
}

[Serializable]
public class uiParamInt : uiParam
{
    public uiParamInt()
    {
		Type = uiParam.emType.TYPE_INT;
    }
    int m_iValue;
    public int Value
    {
        get { return m_iValue; }
        set { m_iValue = value; }
    }
    int m_iMin, m_iMax;
    public void SetScope(int iMin, int iMax)
    {
        m_iMax = iMax;
        m_iMin = iMin;
    }
    public void GetScope(ref int iMin, ref int iMax)
    {
        iMin = m_iMin;
        iMax = m_iMax;
    }
	public override void CreateUI()
	{
		m_iValue = CreateIntInput (Des, m_iValue, m_iMin, m_iMax);
	}
}

[Serializable]
public class uiParamString : uiParam
{
    public uiParamString()
    {
		Type = uiParam.emType.TYPE_STRING;
    }
    string m_strValue;
    public string Value
    {
        get { return m_strValue; }
        set { m_strValue = value; }
    }
    public override void CreateUI()
    {
        m_strValue = CreateStringInput(Des, m_strValue);
    }
}

[Serializable]
public class uiParamList : uiParam
{
    public uiParamList()
    {
		Type = uiParam.emType.TYPE_LIST;
    }
	int m_iSelIndex;
    public int SelIndex
    {
        get { return m_iSelIndex; }
        set { m_iSelIndex = value; }
    }
    string[] m_lsValue;
    public string[] ListValue
    {
        get { return m_lsValue; }
        set { m_lsValue = value; }
    }

    public override void CreateUI()
    {
		m_iSelIndex = CreateListInput(Des, m_lsValue,m_iSelIndex);
    }
}

[Serializable]
public class uiParamOffset : uiParam
{
    public uiParamOffset()
    {
		Type = uiParam.emType.TYPE_OFFSET;
    }
    float m_xAxis, m_yAxis, m_zAxis;
    float m_OffsetValue;
    public float OffsetValue
    {
        get { return m_OffsetValue; }
        set { m_OffsetValue = value; }
    }
    float m_fMin, m_fMax;
    public void SetAxis(float xAxis, float yAxis, float zAxis)
    {
        m_xAxis = xAxis;
        m_yAxis = yAxis;
        m_zAxis = zAxis;
    }

    public void GetAxis(ref float xAxis, ref float yAxis, ref float zAxis)
    {
        xAxis = m_xAxis;
        yAxis = m_yAxis;
        zAxis = m_zAxis;
    }

    public void SetScope(float fMin, float fMax)
    {
        m_fMax = fMax;
        m_fMin = fMin;
    }

    public void GetScope(ref float fMin, ref float fMax)
    {
        fMin = m_fMin;
        fMax = m_fMax;
    }

    public override void CreateUI()
    {
        GUILayout.Label(Des);
        UnityEngine.Vector3 fIn = new UnityEngine.Vector3(m_xAxis, m_yAxis, m_zAxis);
        fIn = CreateEditAxis("偏移轴", fIn);
        SetAxis(fIn[0], fIn[1], fIn[2]);
		m_OffsetValue = CreateRealInput("偏移值", m_OffsetValue, m_fMin, m_fMax);
    }
}

[Serializable]
public class uiParamRotate : uiParam
{
    public uiParamRotate()
    {
		Type = uiParam.emType.TYPE_ROTATE;
    }
    float m_xAxis, m_yAxis, m_zAxis;
    float m_RotateValue;
    public float RotateValue
    {
        get { return m_RotateValue; }
        set { m_RotateValue = value; }
    }
    float m_fMin, m_fMax;
    public void SetAxis(float xAxis, float yAxis, float zAxis)
    {
        m_xAxis = xAxis;
        m_yAxis = yAxis;
        m_zAxis = zAxis;
    }

    public void GetAxis(ref float xAxis, ref float yAxis, ref float zAxis)
    {
        xAxis = m_xAxis;
        yAxis = m_yAxis;
        zAxis = m_zAxis;
    }

    public void SetScope(float fMin, float fMax)
    {
        m_fMax = fMax;
        m_fMin = fMin;
    }

    public void GetScope(ref float fMin, ref float fMax)
    {
        fMin = m_fMin;
        fMax = m_fMax;
    }
    public override void CreateUI()
    {
        GUILayout.Label(Des);
        UnityEngine.Vector3 fIn = new UnityEngine.Vector3(m_xAxis, m_yAxis, m_zAxis);
        fIn = CreateEditAxis("旋转轴", fIn);
        SetAxis(fIn[0], fIn[1], fIn[2]);
		m_RotateValue = CreateRealInput("旋转值", m_RotateValue, m_fMin, m_fMax);
    }
}